package com.webchat.chat.service.impl;

import com.google.common.collect.Lists;
import com.webchat.chat.core.AbstractService;
import com.webchat.chat.core.baseEntity.Result;
import com.webchat.chat.core.baseEntity.ResultGenerator;
import com.webchat.chat.core.enums.UserAccountLockedStatus;
import com.webchat.chat.core.enums.UserAccountType;
import com.webchat.chat.core.enums.UserOnlineStatus;
import com.webchat.chat.core.exception.ServiceException;
import com.webchat.chat.core.redis.RedisService;
import com.webchat.chat.core.tools.RedisConstant;
import com.webchat.chat.core.tools.SaltUtil;
import com.webchat.chat.core.tools.ShiroUtil;
import com.webchat.chat.dao.RoleMapper;
import com.webchat.chat.dao.UserMapper;
import com.webchat.chat.dao.UserRoleMapper;
import com.webchat.chat.model.Role;
import com.webchat.chat.model.SocketClient;
import com.webchat.chat.model.User;
import com.webchat.chat.model.UserRole;
import com.webchat.chat.service.UserService;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.mgt.eis.SessionDAO;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;

import static com.webchat.chat.core.tools.RedisConstant.SCOKET_CLIENT_CS;


/**
 * Created by admin on 2018-06-29.
 */
@Service
@Transactional
public class UserServiceImpl extends AbstractService<User> implements UserService {
    @Resource
    private UserMapper userMapper;
    @Resource
    private RoleMapper roleMapper;
    @Resource
    private UserRoleMapper userRoleMapper;
    @Resource
    private RedisService redisService;
    @Resource
    private SessionDAO sessionDAO;

    @Override
    public void addUser(User user, String[] roleIds) {
        //必要参数校验
        String roleId = roleIds[0];
        Role role = roleMapper.selectByPrimaryKey(roleId);
        if (role == null) {
            throw new ServiceException("所选角色不存在");
        }
        UserAccountType roleType = role.getRoleType();
        String createUserName = user.getUserName();
        String tenantCode = user.getTenantCode();
        String pwdSalt = SaltUtil.getSalt(createUserName, user.getPwdLogin());
        UserAccountType accountType = user.getAccountType();
        user.setPwdSalt(pwdSalt);
        user.setPwdLogin(SaltUtil.encodeMd5Hash(user.getPwdLogin(), pwdSalt));
        //角色和账户类型校验
        if (!Objects.equals(roleType, accountType)) {
            throw new ServiceException("[" + accountType + "]类型的用户不能拥有[" + roleType + "]的角色!");
        }
        List<User> haveUser = userMapper.selectByUserNameAndTenantCode(createUserName, tenantCode);
        if (haveUser != null && !haveUser.isEmpty()) {
            throw new ServiceException("用户名重复，请更换！");
        }
        //保存用户
        String nickName = user.getNickName();
        if (StringUtils.isBlank(nickName)) {
            user.setNickName(user.getUserName());
        }
        user.setAccountLocked(UserAccountLockedStatus.正常);
        user.setOnlineStatus(UserOnlineStatus.离线);
        //附属信息
        Date now = new Date();
        user.setCreatedBy(ShiroUtil.getUserName());
        user.setCreatedDate(now);
        user.setLastModifiedDate(now);
        userMapper.insert(user);
        User userCondition = new User();
        userCondition.setTenantCode(tenantCode);
        userCondition.setUserName(createUserName);
        User addAfterUser = userMapper.selectOne(userCondition);
        //保存用户角色
        UserRole userRole = new UserRole();
        userRole.setRoleId(roleId);
        userRole.setUserId(addAfterUser.getId());
        userRoleMapper.insert(userRole);
        for (int i = 1; i < roleIds.length; i++) {
            UserRole useRole = new UserRole();
            useRole.setRoleId(roleIds[i]);
            useRole.setUserId(addAfterUser.getId());
            userRoleMapper.insert(useRole);
        }
    }


    @Override
    public List<SocketClient> getAvailableCS(String tenantCode) {
        if (StringUtils.isBlank(tenantCode)) {
            return null;
        }
        Map<String, SocketClient> allCS = redisService.getMap(SCOKET_CLIENT_CS + tenantCode);
        if (allCS == null || allCS.isEmpty()) {
            return null;
        }
        ArrayList<SocketClient> availableCS = Lists.newArrayList();
        allCS.forEach((k, v) -> {
            if (v.getConnected()) {
                availableCS.add(v);
            }
        });
        return availableCS;
    }


    @Override
    public void deleteById(String id) {
        UserRole userRoleCondition = new UserRole();
        userRoleCondition.setUserId(id);
        List<UserRole> selectUserRole = userRoleMapper.select(userRoleCondition);
        selectUserRole.forEach(userRole -> {
            userMapper.deleteByPrimaryKey(userRole.getId());
        });
        super.deleteById(id);
    }


    @Override
    public User findDetailById(String id) {
        User user = super.findById(id);
        List<Role> roles = roleMapper.findRolesByUserId(id);
       /* if (roles == null || roles.isEmpty()) {
            throw new ServiceException("该用户尚未分配角色！！");
        }*/
        user.setUserRoles(roles);
        return user;
    }

    @Override
    public void updateUserAndRole(User user, String[] roleIds) {
        String userId = user.getId();
        if (StringUtils.isBlank(userId)) {
            throw new ServiceException("用户Id不能为空，请输入用户id ！！");
        }

        //根据角色修改用户的类型
        User us = super.findById(userId);
        List<Role> roleList = new ArrayList<>();
        for (String roleId : roleIds) {
            Role role = roleMapper.selectByPrimaryKey(roleId);
            roleList.add(role);
        }
        us.setAccountType(UserAccountType.客服);
        for (Role role : roleList) {
            if (Objects.equals(UserAccountType.管理员, role.getRoleType())) {
                us.setAccountType(UserAccountType.管理员);
                break;
            }
        }
        userMapper.updateByPrimaryKey(us);

        //删除已有的角色
        UserRole userR = new UserRole();
        userR.setUserId(userId);
        userRoleMapper.delete(userR);

        //更新用户角色
        for (Role role : roleList) {
            UserRole userRole = new UserRole();
            userRole.setRoleId(role.getId());
            userRole.setUserId(userId);
            userRoleMapper.insert(userRole);
        }
    }


    public Result checkUser(User user) {

        //添加用户,必须保证入参有用户名,密码,账号类型
        String userName = user.getUserName();
        String pwdLogin = user.getPwdLogin();
        UserAccountType accountType = user.getAccountType();
        if (StringUtils.isBlank(userName) || StringUtils.isBlank(pwdLogin)) {
            return ResultGenerator.genFailResult("用户名和密码必填");
        }
        if (accountType == null) {
            return ResultGenerator.genFailResult("账号类型必填");
        }
        return ResultGenerator.genSuccessResult();
    }

    @Override
    public List<User> findUserByInfo(User user) {
        List<User> userList = userMapper.findUserByInfo(user);
        return userList;
    }


    /**
     * 根据用户id 踢出在线用户
     * @date 2018/8/2 10:58
     * @author lion
     *
     */
    @Override
    public Boolean ckeckAlreadyOnlineAndKickout(String userId) {
        Boolean flag=false;
        Map<String, String> sessionMap = redisService.getMap(RedisConstant.User_Session+ShiroUtil.getTenantCode());
        if (sessionMap.size() > 0 && !sessionMap.isEmpty() && sessionMap.containsKey(userId)) {
            String sessionId = sessionMap.get(userId);
            // 不使用 sessionDAO.readSession(sessionId);避免session不存在，直接异常
            Collection<Session> sessions = sessionDAO.getActiveSessions();
            for (Session session: sessions) {
                if(StringUtils.equals(sessionId, session.getId().toString())){
                    sessionDAO.delete(session);
                    flag = true;
                    break;
                }
            }
        } else {
            sessionMap = new HashMap<>();
        }

        // 踢出的id与操作者id相同，第二次登录则更新redis； 不同，管理员踢出用户则修改离线  (判断是登录验证，还是管理员踢出用户)
        if (StringUtils.equals(userId, ShiroUtil.getUserId())){
            sessionMap.put(userId, SecurityUtils.getSubject().getSession().getId().toString());
        }else {
            sessionMap.remove(userId);
            changeStatusOffline(userId);
        }

        redisService.addMap(RedisConstant.User_Session+ShiroUtil.getTenantCode(), sessionMap);
        return flag;
    }

    @Override
    public void updateUser(User user) {
        String createUserName = user.getUserName();
        if (StringUtils.isNotBlank(user.getPwdLogin())){
            String pwdSalt = SaltUtil.getSalt(createUserName, user.getPwdLogin());
            user.setPwdSalt(pwdSalt);
            user.setPwdLogin(SaltUtil.encodeMd5Hash(user.getPwdLogin(), pwdSalt));
        }
        super.update(user);
    }
    @Override
    public void changeStatusOffline(String userId) {
        User user = userMapper.selectByPrimaryKey(userId);
        user.setOnlineStatus(UserOnlineStatus.离线);
        userMapper.updateByPrimaryKey(user);
        redisService.removeMapField(RedisConstant.User_Session+ShiroUtil.getTenantCode(),userId);
    }

    @Override
    public List<User> findAllByTenantCode() {
        User user = new User();
        if("All".equals(ShiroUtil.getTenantCode())){
            return   userMapper.selectAll();
        }
        user.setTenantCode(ShiroUtil.getTenantCode());
        return userMapper.select(user);
    }
}
